﻿using System;
using System.Web;
using System.Web.Mvc;
using NHibernate;
using Ornament.NHibernates;

namespace Ornament.Web.Mvc
{
    /// <summary>
    /// 
    /// </summary>
    public abstract class BaseModelBinder : DefaultModelBinder, IDisposable
    {
        #region IDisposable Members

        public void Dispose()
        {
            SessionManager.Instance.CleanUp();
        }

        #endregion

        /// <summary>
        /// Request Id from HttpRequest
        /// </summary>
        /// <param name="request"></param>
        /// <returns>Id of the Domain object</returns>
        protected abstract object RequestId(HttpRequestBase request);

        /// <summary>
        /// Create the Model 
        /// </summary>
        /// <param name="controllerContext"></param>
        /// <param name="bindingContext"></param>
        /// <param name="modelType"></param>
        /// <returns></returns>
        protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext,
                                              Type modelType)
        {
            SessionManager.Instance.IniSession();
            ISession currentSession = SessionManager.Instance.CurrentSession;
            HttpRequestBase request = controllerContext.RequestContext.HttpContext.Request;
            return RequestId(request) == null
                       ? CreateNewObject(controllerContext, bindingContext, modelType)
                       : (GetObjectByNh(currentSession, modelType, RequestId(request), request)
                          ?? CreateNewObject(controllerContext, bindingContext, modelType));
        }

        /// <summary>
        /// Create new object, when can't load domain object from database or
        /// can't get id from property <see cref="RequestId"/>, it will use this function to 
        /// create new object.
        /// </summary>
        /// <param name="controllerContext"></param>
        /// <param name="bindingContext"></param>
        /// <param name="modelType"></param>
        /// <returns></returns>
        protected virtual object CreateNewObject(ControllerContext controllerContext, ModelBindingContext bindingContext,
                                                 Type modelType)
        {
            return base.CreateModel(controllerContext, bindingContext, modelType);
        }

        /// <summary>
        /// Load object by NHibernate.
        /// </summary>
        /// <param name="currentSession">nhibernate session</param>
        /// <param name="modelType">the type of the domain object</param>
        /// <param name="id">id of the domain</param>
        /// <param name="request">HttpRequestBase</param>
        /// <returns></returns>
        protected virtual object GetObjectByNh(ISession currentSession, Type modelType, object id,
                                               HttpRequestBase request)
        {
            return currentSession.Get(modelType, RequestId(request));
        }
    }
}